//
// Created by Gao Shihao on 2023/8/31.
//

#ifndef PLC2LLVM_ALIASTYPE_H
#define PLC2LLVM_ALIASTYPE_H

#include <plc2llvm/TypeSystem/UserDefType.h>

namespace plcst {

    // Directly derived data types
    class AliasType: public UserDefType {

    public:

        explicit AliasType(std::string&& name):UserDefType(std::move(name)), basicType() {}

        explicit AliasType(AliasType* another) : UserDefType(another) { }

        [[nodiscard]] TypeKind getTypeKind() const override;

        void setBasicType(std::unique_ptr<BasicType> bt);

        Type* getBasicType();

        virtual ConvertionSignal canConvertTo(std::shared_ptr<Type> dest) override{
            if(this->getTypeKind() == dest->getTypeKind()){ //类型相同
                return ConvertionSignal::IMPLICIT_CONVERSION;
            }
            return ConvertionSignal::ERROR_CONVERSION; // TODO
        }

        virtual TypeMsg typeSynthesisForBinaryOperator(ExpressionOperator op, std::shared_ptr<Type> another) override{
            return {nullptr, 2}; // TODO
        }

        virtual TypeMsg typeSynthesisForUnaryOperator(ExpressionOperator op) override {
            return {nullptr, 2};// TODO
        }

        virtual std::shared_ptr<Type> clone() override {
            return std::make_shared<AliasType>(this);
        }

    private:
        std::unique_ptr<BasicType> basicType;

    };

    void AliasType::setBasicType(std::unique_ptr<BasicType> bt) {
        basicType = std::move(bt);
    }

    Type *AliasType::getBasicType() {
        return basicType.get();
    }

    TypeKind AliasType::getTypeKind() const {
        return TypeKind::DIRECTLY_DERIVED;
    }
}

#endif //PLC2LLVM_ALIASTYPE_H
